5.14. Важные классы и интерфейсы
Важные классы и интерфейсы
1. Основные классы и структуры из стандартной библиотеки Swift
String
Тип String в Swift представляет собой коллекцию символов Unicode. Он является значимым типом (value type), реализует протоколы Collection, ExpressibleByStringLiteral, CustomStringConvertible и другие.
Свойства:
count— количество символов.isEmpty— логическое значение, указывающее, пуста ли строка.first,last— первый и последний символ (опциональные).utf8,utf16,unicodeScalars— представления строки в различных кодировках.
Методы:
hasPrefix(_:),hasSuffix(_:)— проверка наличия префикса или суффикса.components(separatedBy:)— разделение строки на подстроки по заданному разделителю.replacingOccurrences(of:with:)— замена подстроки.lowercased(),uppercased()— приведение к нижнему или верхнему регистру.
Пример использования: обработка пользовательского ввода, парсинг текстовых данных, форматирование сообщений.
Array
Array — упорядоченная коллекция значений одного типа. Это структура, а не класс, и она передаётся по значению.
Свойства:
count,isEmpty— аналогично строке.first,last— доступ к первому и последнему элементу.capacity— текущая ёмкость массива в памяти.
Методы:
append(_:),append(contentsOf:)— добавление элементов.remove(at:),removeLast(),removeAll()— удаление.contains(where:),first(where:),filter(_:)— поиск и фильтрация.map(_:),compactMap(_:),flatMap(_:)— трансформация.sorted(by:),shuffle()— сортировка и перемешивание.
Пример использования: хранение списков данных, работа с результатами API, кэширование объектов.
Dictionary
Dictionary — неупорядоченная коллекция пар «ключ–значение». Ключи должны соответствовать протоколу Hashable.
Свойства:
count,isEmpty.keys,values— коллекции ключей и значений.
Методы:
updateValue(_:forKey:)— обновление или вставка значения.removeValue(forKey:)— удаление по ключу.merge(_:uniquingKeysWith:)— объединение словарей.
Пример использования: конфигурации, кэширование, маппинг идентификаторов на объекты.
Set
Set — неупорядоченная коллекция уникальных значений, соответствующих протоколу Hashable.
Свойства и методы:
insert(_:),remove(_:),contains(_:).- Операции над множествами:
union(_:),intersection(_:),subtracting(_:),symmetricDifference(_:).
Пример использования: отслеживание уникальных событий, проверка принадлежности, исключение дубликатов.
2. Ключевые классы из Foundation
Foundation — это фундаментальный фреймворк Apple, предоставляющий базовые типы данных, операции с файловой системой, сетевыми запросами, датами и многим другим.
NSObject
Базовый класс для всех Objective-C совместимых объектов. В Swift многие классы наследуются от NSObject, особенно при работе с UIKit или Cocoa.
Свойства и методы:
isEqual(_:)— сравнение объектов.hash— хэш-значение.description— текстовое представление объекта.performSelector(_:)— динамический вызов метода (редко используется в чистом Swift).
Применяется при необходимости совместимости с Objective-C API, например, при использовании UserDefaults, NotificationCenter, NSCoding.
URL
Представляет унифицированный ресурсный локатор. Используется для работы с файлами, сетевыми адресами, путями.
Свойства:
absoluteString,path,host,scheme,query— компоненты URL.deletingLastPathComponent(),appendingPathComponent(_:)— манипуляции с путём.
Пример использования: построение запросов к API, работа с локальными файлами, обработка deep links.
Date и Calendar
Date представляет момент времени независимо от часового пояса. Calendar предоставляет методы для работы с календарными компонентами: год, месяц, день, час и т.д.
Методы Calendar:
dateComponents(_:from:)— извлечение компонентов из даты.date(from:)— создание даты из компонентов.isDateInToday(_:),isDate(_:_:toGranularity:)— сравнение дат.
Пример использования: отображение событий по датам, планирование уведомлений, анализ временных меток.
FileManager
Управляет файловой системой: создание, удаление, перемещение файлов и директорий.
Методы:
fileExists(atPath:)— проверка существования файла.contentsOfDirectory(atPath:)— получение списка файлов в папке.createDirectory(atPath:withIntermediateDirectories:attributes:)— создание директории.copyItem(at:to:),moveItem(at:to:),removeItem(at:)— операции с файлами.
Пример использования: сохранение кэша, экспорт данных, работа с документами пользователя.
JSONEncoder / JSONDecoder
Инструменты для сериализации и десериализации объектов в/из JSON. Требуют, чтобы типы соответствовали протоколу Codable.
Пример:
struct User: Codable {
let name: String
let age: Int
}
let user = User(name: "Timur", age: 31)
let encoder = JSONEncoder()
let data = try encoder.encode(user)
let decoder = JSONDecoder()
let restored = try decoder.decode(User.self, from: data)
Применяется при работе с REST API, сохранении состояния, миграции данных.
3. Протоколы (интерфейсы) Swift
Swift делает акцент на протоколах как на основном механизме абстракции. Протоколы определяют контракт, которому должен соответствовать тип.
Equatable
Типы, реализующие Equatable, могут сравниваться с помощью оператора ==.
Пример:
struct Point: Equatable {
let x, y: Int
}
// Автоматическая реализация == доступна, если все свойства Equatable
Comparable
Расширяет Equatable, добавляя возможность упорядочения (<, >, <=, >=).
Пример: сортировка массивов, бинарный поиск.
Hashable
Необходим для использования типа в качестве ключа в Dictionary или элемента в Set. Требует корректной реализации hash(into:) или автоматической генерации.
Codable
Объединяет Encodable и Decodable. Позволяет легко сериализовать структуры и классы.
CustomStringConvertible
Позволяет определить пользовательское текстовое представление через свойство description.
Identifiable
Требует наличие уникального id. Широко используется в SwiftUI для отслеживания изменений в списках.
4. Часто используемые классы в прикладной разработке
UIViewController (UIKit)
Базовый класс контроллера представления в UIKit. Управляет жизненным циклом экрана:
viewDidLoad()— вызывается после загрузки иерархии вью.viewWillAppear(_:),viewDidAppear(_:)— перед и после появления экрана.viewWillDisappear(_:),viewDidDisappear(_:)— перед и после исчезновения.
Свойства:
view— корневое представление контроллера.navigationController,tabBarController— ссылки на родительские контейнеры.
Применяется в каждом экране приложения, построенного на UIKit.
View (SwiftUI)
В SwiftUI всё строится на декларативных представлениях, соответствующих протоколу View.
Пример:
struct ContentView: View {
var body: some View {
Text("Hello")
}
}
Ключевые модификаторы: padding(), frame(), onAppear(), navigationTitle(_:).
ObservableObject и @Published
Используются для управления состоянием в SwiftUI. Класс, соответствующий ObservableObject, может публиковать изменения через свойства с аннотацией @Published.
Пример:
class AppState: ObservableObject {
@Published var isLoggedIn = false
}
В представлении используется @ObservedObject или @StateObject.
URLSession
Основной инструмент для выполнения сетевых запросов.
Методы:
dataTask(with:completionHandler:)— асинхронный запрос данных.downloadTask(with:completionHandler:)— загрузка файла.uploadTask(with:from:completionHandler:)— отправка данных.
Пример:
let url = URL(string: "https://api.example.com/data")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
// Обработка ответа
}
task.resume()
Применяется в любом приложении, взаимодействующем с сервером.
NotificationCenter
Позволяет реализовать паттерн «наблюдатель» (observer).
Методы:
addObserver(forName:object:queue:using:)— подписка на уведомление.post(name:object:userInfo:)— отправка уведомления.
Пример: реакция на смену темы, обновление данных после завершения фоновой задачи.
UserDefaults
Хранение небольших объёмов данных в виде пар «ключ–значение». Поддерживает примитивы, Data, URL, Array и Dictionary из поддерживаемых типов.
Методы:
set(_:forKey:),string(forKey:),bool(forKey:),synchronize().
Пример: сохранение настроек, флага первого запуска, токена авторизации.
5. Практические сценарии и выбор инструментов
Сценарий 1: Загрузка и отображение списка пользователей
- Используется
URLSessionдля запроса к API. - Ответ десериализуется через
JSONDecoderв массив структур, соответствующихCodable. - Данные передаются в
UITableView(UIKit) илиList(SwiftUI). - Для обновления интерфейса применяется
DispatchQueue.main.asyncили@Published+ObservableObject.
Сценарий 2: Сохранение состояния между запусками
- Небольшие данные (например, настройки) —
UserDefaults. - Сложные структуры — сериализация в
DataчерезJSONEncoderи сохранение в файл черезFileManager.
Сценарий 3: Реакция на системные события
- Подписка на
UIApplication.willEnterForegroundNotificationчерезNotificationCenter. - Обновление UI или данных при возвращении в приложение.
Сценарий 4: Работа с датами и временем
- Использование
DateFormatterдля отображения дат в локализованном виде. Calendarдля вычисления разницы между датами или определения дня недели.
6. Работа с асинхронностью и потоками выполнения
Swift предоставляет мощные инструменты для управления параллельным и асинхронным кодом. Современные приложения почти всегда взаимодействуют с сетью, файловой системой или выполняют вычисления, которые не должны блокировать основной поток пользовательского интерфейса.
DispatchQueue (Grand Central Dispatch)
DispatchQueue — это механизм Apple для управления очередями задач. Он позволяет выполнять код синхронно или асинхронно на глобальных, пользовательских или главном потоке.
Основные типы очередей:
- Main queue — привязана к главному потоку, используется для обновления UI.
- Global queues — системные фоновые очереди с разными уровнями приоритета (
userInteractive,userInitiated,default,utility,background). - Custom serial/concurrent queues — создаваемые разработчиком последовательные или параллельные очереди.
Методы:
async(execute:)— асинхронное выполнение замыкания.sync(execute:)— синхронное выполнение (блокирует текущий поток до завершения).asyncAfter(deadline:execute:)— отложенное выполнение.
Пример:
DispatchQueue.global(qos: .userInitiated).async {
// Тяжёлая операция: парсинг, загрузка, расчёт
let result = performExpensiveCalculation()
DispatchQueue.main.async {
// Обновление интерфейса
label.text = "Результат: \(result)"
}
}
async/await (начиная с Swift 5.5)
Swift внедрил современную модель асинхронного программирования на основе ключевых слов async и await. Это позволяет писать асинхронный код в линейном стиле без вложенных замыканий.
Функция, помеченная как async, может быть вызвана только из другого асинхронного контекста или с использованием await.
Пример:
func fetchData(from url: URL) async throws -> Data {
let (data, _) = try await URLSession.shared.data(from: url)
return data
}
// Вызов
Task {
do {
let data = try await fetchData(from: someURL)
// Обработка данных
} catch {
// Обработка ошибки
}
}
Task и TaskGroup
Task — это единица асинхронной работы. TaskGroup позволяет запускать несколько задач параллельно и собирать их результаты.
Пример параллельной загрузки:
let urls = [url1, url2, url3]
let results = await withTaskGroup(of: Data.self) { group in
for url in urls {
group.addTask {
return try await fetchData(from: url)
}
}
return await group.reduce(into: []) { $0.append($1) }
}
Эти инструменты особенно полезны при работе с множественными API-запросами, фоновой обработкой изображений или синхронизацией данных.
7. Работа с уведомлениями и событиями
NotificationCenter
Как уже упоминалось, NotificationCenter реализует паттерн «наблюдатель». Он позволяет отправлять и получать уведомления по имени.
Часто используемые системные уведомления:
UIApplication.willEnterForegroundNotificationUIApplication.didBecomeActiveNotificationUIContentSizeCategory.didChangeNotification— изменение размера шрифта в системе
Пример подписки:
let observer = NotificationCenter.default.addObserver(
forName: UIDevice.batteryLevelDidChangeNotification,
object: nil,
queue: .main
) { _ in
print("Уровень заряда изменился")
}
Важно отписываться от уведомлений во избежание утечек памяти, особенно в UIViewController — в методе deinit или viewWillDisappear.
Combine Framework
Начиная с iOS 13, Apple представила фреймворк Combine — реактивное программирование на основе издателей (Publisher) и подписчиков (Subscriber).
Ключевые протоколы:
Publisher— генерирует значения во времени.Subscriber— получает значения и завершение.
Часто используемые издатели:
@Published— автоматически создаётPublishedиздатель при изменении свойства.URLSession.dataTaskPublisher— возвращает данные из сети как поток.Timer.publish(every:tolerance:on:in:options:)— периодическая генерация событий.
Операторы трансформации:
map,filter,compactMapdebounce,throttle— ограничение частоты событийreceive(on:)— переключение очереди выполненияsink— подписка на значения
Пример:
class ViewModel: ObservableObject {
@Published var userName = ""
private var cancellables = Set<AnyCancellable>()
init() {
$userName
.debounce(for: .milliseconds(500), scheduler: RunLoop.main)
.removeDuplicates()
.sink { name in
print("Поиск по запросу: \(name)")
}
.store(in: &cancellables)
}
}
Combine особенно эффективен в связке с SwiftUI, где изменения состояния автоматически приводят к перерисовке интерфейса.
8. Работа с локализацией и ресурсами
Bundle
Класс Bundle предоставляет доступ к ресурсам приложения: изображениям, звукам, локализованным строкам, файлам конфигурации.
Методы:
url(forResource:withExtension:)— получение URL файла по имени и расширению.path(forResource:ofType:)— путь к ресурсу.localizedString(forKey:value:table:)— получение локализованной строки.
Пример:
if let path = Bundle.main.path(forResource: "config", ofType: "json") {
let data = try Data(contentsOf: URL(fileURLWithPath: path))
// Парсинг конфигурации
}
LocalizedStringKey и NSLocalizedString
В SwiftUI используется Text("Hello"), где строка автоматически интерпретируется как ключ локализации. В UIKit применяется NSLocalizedString("greeting", comment: "").
Файлы локализации (Localizable.strings) содержат пары:
"greeting" = "Приветствие";
"settings_title" = "Настройки";
Поддержка нескольких языков достигается через папки ru.lproj, en.lproj и т.д.
9. Безопасность и работа с ключами
Keychain Services
Для хранения чувствительных данных (токены, пароли, ключи шифрования) используется Keychain, а не UserDefaults.
Swift-обёртки (например, KeychainAccess или собственные решения) упрощают работу с низкоуровневым C API.
Пример сохранения:
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "authToken",
kSecValueData as String: token.data(using: .utf8)!
]
SecItemAdd(query as CFDictionary, nil)
Получение:
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "authToken",
kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitOne
]
var result: AnyObject?
SecItemCopyMatching(query as CFDictionary, &result)
if let data = result as? Data, let token = String(data: data, encoding: .utf8) {
// Использование токена
}
Keychain обеспечивает шифрование на уровне устройства и сохраняет данные даже после удаления приложения (если не указано иное).
10. Архитектурные паттерны и организация кода
Хотя Swift сам по себе не диктует архитектуру, в экосистеме Apple сложились устоявшиеся подходы:
- MVC (Model-View-Controller) — стандарт UIKit, где
UIViewControllerуправляет логикой и представлением. - MVVM (Model-View-ViewModel) — популярен в SwiftUI, где
ViewModel(частоObservableObject) содержит состояние и логику, аView— только отображение. - Coordinator — паттерн для управления навигацией, особенно в UIKit.
Ключевые принципы:
- Разделение ответственности.
- Минимизация логики в
View. - Использование протоколов для зависимостей.
- Изоляция сетевого слоя (
NetworkService), слоя данных (Repository), бизнес-логики (UseCase).
Пример структуры проекта:
Sources/
├── Models/
│ └── User.swift
├── Views/
│ └── ProfileView.swift
├── ViewModels/
│ └── ProfileViewModel.swift
├── Services/
│ ├── NetworkService.swift
│ └── AuthService.swift
├── Repositories/
│ └── UserRepository.swift
└── Utils/
└── Extensions.swift
Такая организация повышает тестируемость, читаемость и поддерживаемость.